home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / wgdb-42.lha / wgdb-4.2 / gdb / nindy-share / nindy.c < prev    next >
C/C++ Source or Header  |  1992-09-11  |  40KB  |  1,464 lines

  1. /*****************************************************************************
  2.  *         Copyright (c) 1990, Intel Corporation
  3.  *
  4.  * Intel hereby grants you permission to copy, modify, and 
  5.  * distribute this software and its documentation.  Intel grants
  6.  * this permission provided that the above copyright notice 
  7.  * appears in all copies and that both the copyright notice and
  8.  * this permission notice appear in supporting documentation.  In
  9.  * addition, Intel grants this permission provided that you
  10.  * prominently mark as not part of the original any modifications
  11.  * made to this software or documentation, and that the name of 
  12.  * Intel Corporation not be used in advertising or publicity 
  13.  * pertaining to distribution of the software or the documentation 
  14.  * without specific, written prior permission.  
  15.  *
  16.  * Intel Corporation does not warrant, guarantee or make any 
  17.  * representations regarding the use of, or the results of the use
  18.  * of, the software and documentation in terms of correctness, 
  19.  * accuracy, reliability, currentness, or otherwise; and you rely
  20.  * on the software, documentation and results solely at your own risk.
  21.  *****************************************************************************/
  22.  
  23. static char rcsid[] =
  24.     "Id: nindy.c,v 1.1.1.1 1991/03/28 16:20:57 rich Exp $";
  25.  
  26. /******************************************************************************
  27.  *
  28.  *             NINDY INTERFACE ROUTINES
  29.  *
  30.  * The routines in this file define and implement an interface between code
  31.  * (such as a high-level debugger) running on a remote host and the NINDY
  32.  * ROM monitor on an i960 board.  These routines are to be linked with 
  33.  * and called by the host code.
  34.  *
  35.  * These routines handle both the formatting/transferring of commands to NINDY
  36.  * and the receipt/formatting of data returned in response to them.  The
  37.  * actual transfer protocol is hidden from the host programmer within them.
  38.  * For a full description of the lowest level NINDY/host transfer protocol,
  39.  * see the block header of the file gdb.c, in the NINDY source code.
  40.  *
  41.  * The caller of these routines should be aware that:
  42.  *
  43.  * (1) ninConnect() should be called to open communications with the
  44.  *     remote NINDY board before any of the other routines are invoked.
  45.  *
  46.  * (2) almost all interactions are driven by the host: nindy sends information
  47.  *     in response to host commands.
  48.  *
  49.  * (3) the lone exception to (2) is the single character DLE (^P, 0x10).
  50.  *     Receipt of a DLE from NINDY indicates that the application program
  51.  *     running under NINDY has stopped execution and that NINDY is now
  52.  *     available to talk to the host (all other communication received after
  53.  *     the application has been started should be presumed to come from the
  54.  *     application and should be passed on by the host to stdout).
  55.  *
  56.  * (4) the reason the application program stopped can be determined with the
  57.  *     ninStopWhy() function.  There are three classes of stop reasons:
  58.  *
  59.  *    (a) the application has terminated execution.
  60.  *        The host should take appropriate action.
  61.  *
  62.  *    (b) the application had a fault or trace event.
  63.  *        The host should take appropriate action.
  64.  *
  65.  *    (c) the application wishes to make a service request (srq) of the host;
  66.  *        e.g., to open/close a file, read/write a file, etc.  The ninSrq()
  67.  *        function should be called to determine the nature of the request
  68.  *        and process it.
  69.  *
  70.  * WARNING: Changes made here should be tested in both gdb960 and comm960.
  71.  *
  72.  ******************************************************************************/
  73.  
  74. #include <stdio.h>
  75. #include <sys/ioctl.h>
  76. #include <sys/types.h>    /* Needed by file.h on Sys V */
  77. #include <sys/file.h>
  78. #include <signal.h>
  79. #include <sys/stat.h>
  80. #include <fcntl.h>    /* Needed on Sys V */
  81. #include "ttycntl.h"
  82. #include "block_io.h"
  83. #include "wait.h"
  84. #include "env.h"
  85.  
  86.  
  87. #ifdef USG
  88. #    include <unistd.h>
  89. #    include "sysv.h"
  90. #else    /* BSD */
  91. #    include "string.h"
  92. #    include <sys/time.h>
  93. #endif
  94.  
  95. #ifndef ERROR
  96. #define ERROR    -1
  97. #endif
  98.  
  99. #define DLE    0x10    /* ^P */
  100. #define XON    0x11    /* ^Q */
  101. #define XOFF    0x13    /* ^S */
  102. #define ESC    0x1b
  103.  
  104.  
  105. #define REGISTER_BYTES    ((36*4) + (4*8))
  106.  
  107. #define TIMEOUT        -1
  108.  
  109. extern char *malloc();
  110. extern void free();
  111.  
  112. static int quiet = 0;    /* 1 => stifle unnecessary messages */
  113. static int nindy_fd;    /* File descriptor of tty connected to 960/NINDY board*/
  114.  
  115. static int old_nindy = 0; /* 1 => use old (hex) communication protocol */
  116. static ninStrGet();
  117.  
  118.         /****************************
  119.          *                          *
  120.          *  MISCELLANEOUS UTILTIES  *
  121.          *                          *
  122.          ****************************/
  123.  
  124.  
  125. #if 0
  126. /******************************************************************************
  127.  * byteswap:
  128.  *    If the host byte order is different from 960 byte order (i.e., the
  129.  *    host is big-endian), reverse the bytes in the passed value;  otherwise,
  130.  *    return the passed value unchanged.
  131.  *
  132.  ******************************************************************************/
  133. static
  134. long
  135. byteswap( n )
  136.     long n;
  137. {
  138.     long rev;
  139.     int i;
  140.     static short test = 0x1234;
  141.  
  142.     if (*((char *) &test) == 0x12) {
  143.         /*
  144.          * Big-endian host, swap the bytes.
  145.          */
  146.         rev = 0;
  147.         for ( i = 0; i < sizeof(n); i++ ){
  148.             rev <<= 8;
  149.             rev |= n & 0xff;
  150.             n >>= 8;
  151.         }
  152.         n = rev;
  153.     }
  154.     return n;
  155. }
  156. #endif 
  157.  
  158.  
  159. /******************************************************************************
  160.  * get_int:
  161.  *    Copy the little-endian integer pointed at by 'p'  and return it in
  162.  *    the host byte order.  'p' may be an unaligned address, so do the copy
  163.  *    a byte at a time.
  164.  ******************************************************************************/
  165. int
  166. get_int( p )
  167.     unsigned char *p;
  168. {
  169.     int n;
  170.     int i;
  171.  
  172.     n = 0;
  173.     p += sizeof(int) - 1;
  174.     for ( i = 0; i < sizeof(n); i++ ){
  175.         n <<= 8;
  176.         n |= *p--;
  177.     }
  178.  
  179.     return n;
  180. }
  181.  
  182.  
  183. /******************************************************************************
  184.  * put_int:
  185.  *    Copy the integer 'n' (which is in host byte order) to the location
  186.  *    pointed at by 'p', leaving it in little-endian byte order.
  187.  *    'p' may be an unaligned address, so do the move a byte at a time.
  188.  ******************************************************************************/
  189. int
  190. put_int( p, n )
  191.     unsigned char *p;
  192.     int n;
  193. {
  194.     int i;
  195.  
  196.     for ( i = 0; i < sizeof(n); i++ ){
  197.         *p++ = n;
  198.         n >>= 8;
  199.     }
  200. }
  201.  
  202.  
  203. /******************************************************************************
  204.  * say:
  205.  *    This is a printf that takes at most two arguments (in addition to the
  206.  *    format string) and that outputs nothing if verbose output has been
  207.  *    suppressed.
  208.  ******************************************************************************/
  209. /* FIXME: use varargs for this.  */
  210. static
  211. say( fmt, arg1, arg2 )
  212.     char *fmt;
  213.     int arg1, arg2;
  214. {
  215.     if ( !quiet ){
  216.         printf( fmt, arg1, arg2 );
  217.         fflush( stdout );
  218.     }
  219. }
  220.  
  221. /******************************************************************************
  222.  * exists:
  223.  *    Creates a full pathname by concatenating up to three name components
  224.  *    onto a specified base name; optionally looks up the base name as a
  225.  *    runtime environment variable;  and checks to see if the file or
  226.  *    directory specified by the pathname actually exists.
  227.  *
  228.  *    Returns:  the full pathname if it exists, NULL otherwise.
  229.  *        (returned pathname is in malloc'd memory and must be freed
  230.  *        by caller).
  231.  *****************************************************************************/
  232. static
  233. char *
  234. exists( base, c1, c2, c3, env )
  235.     char *base;        /* Base directory of path */
  236.     char *c1, *c2, *c3;    /* Components (subdirectories and/or file name) to be
  237.              *    appended onto the base directory name.  One or
  238.              *    more may be omitted by passing NULL pointers.
  239.              */
  240.     int env;        /* If 1, '*base' is the name of an environment variable
  241.              *    to be examined for the base directory name;
  242.              *    otherwise, '*base' is the actual name of the
  243.              *    base directory.
  244.              */
  245. {
  246.     struct stat buf;/* For call to 'stat' -- never examined */
  247.     char *path;    /* Pointer to full pathname (malloc'd memory) */
  248.     int len;    /* Length of full pathname (incl. terminator) */
  249.     extern char *getenv();
  250.  
  251.  
  252.     if ( env ){
  253.         base = getenv( base );
  254.         if ( base == NULL ){
  255.             return NULL;
  256.         }
  257.     }
  258.  
  259.     len = strlen(base) + 4;
  260.             /* +4 for terminator and "/" before each component */
  261.     if ( c1 != NULL ){
  262.         len += strlen(c1);
  263.     }
  264.     if ( c2 != NULL ){
  265.         len += strlen(c2);
  266.     }
  267.     if ( c3 != NULL ){
  268.         len += strlen(c3);
  269.     }
  270.  
  271.     path = malloc( len );
  272.  
  273.     strcpy( path, base );
  274.     if ( c1 != NULL ){
  275.         strcat( path, "/" );
  276.         strcat( path, c1 );
  277.         if ( c2 != NULL ){
  278.             strcat( path, "/" );
  279.             strcat( path, c2 );
  280.             if ( c3 != NULL ){
  281.                 strcat( path, "/" );
  282.                 strcat( path, c3 );
  283.             }
  284.         }
  285.     }
  286.  
  287.     if ( stat(path,&buf) != 0 ){
  288.         free( path );
  289.         path = NULL;
  290.     }
  291.     return path;
  292. }
  293.  
  294.         /*****************************
  295.          *                           *
  296.          *  LOW-LEVEL COMMUNICATION  *
  297.          *                           *
  298.          *****************************/
  299.  
  300. /******************************************************************************
  301.  * timed_read:
  302.  *    Read up to 'n' characters (less if fewer are available) from the NINDY
  303.  *    tty. Wait up to 'timeout' seconds for something to arrive.  Return
  304.  *    the number of characters read, 0 on timeout.
  305.  ******************************************************************************/
  306. #ifdef USG
  307.  
  308. static int saw_alarm;
  309.  
  310. static void
  311. alarm_handler()
  312. {
  313.     saw_alarm = 1;
  314. }
  315.  
  316. static
  317. int
  318. timed_read(buf,n,timeout)
  319.     unsigned char * buf;    /* Where to put the read characters    */
  320.     int n;            /* Max number of characters to read    */
  321.     int timeout;        /* Timeout, in seconds            */
  322. {
  323.         void (*old_alarm)();    /* Save alarm signal handler here on entry */
  324.     int cnt;
  325.  
  326.  
  327.         old_alarm = signal( SIGALRM,alarm_handler );
  328.         saw_alarm = 0;
  329.         alarm(timeout);
  330.         do {
  331.         cnt = n;
  332.                 TTY_NBREAD(nindy_fd,cnt,buf);
  333.         } while ( (cnt <= 0) && !saw_alarm );
  334.  
  335.         alarm(0);
  336.         signal( SIGALRM,old_alarm );
  337.  
  338.     return saw_alarm ? 0 : cnt;
  339. }
  340.  
  341. #else        /* BSD */
  342.  
  343. static
  344. int
  345. timed_read(buf,n,timeout)
  346.     unsigned char * buf;    /* Where to put the read characters    */
  347.     int n;            /* Max number of characters to read    */
  348.     int timeout;        /* Timeout, in seconds            */
  349. {
  350.     struct timeval t;
  351.     fd_set f;
  352.  
  353.     t.tv_sec = (long) timeout;
  354.     t.tv_usec= 0;
  355.  
  356.     FD_ZERO( &f );
  357.     FD_SET( nindy_fd, &f );
  358.     if ( select(nindy_fd+1,&f,0,0,&t) ){
  359.         return read( nindy_fd, buf, n );
  360.     } else {
  361.         return 0;
  362.     }
  363. }
  364. #endif
  365.  
  366. /******************************************************************************
  367.  * rdnin:
  368.  *    Read *exactly* 'n' characters from the NINDY tty.  Translate escape
  369.  *    sequences into single characters, counting each such sequence as 
  370.  *    1 character.
  371.  *
  372.  *    An escape sequence consists of ESC and a following character.  The
  373.  *    ESC is discarded and the other character gets bit 0x40 cleared --
  374.  *    thus ESC P == ^P, ESC S == ^S, ESC [ == ESC, etc.
  375.  *
  376.  *    Return 1 if successful, 0 if more than 'timeout' seconds pass without
  377.  *    any input.
  378.  ******************************************************************************/
  379. static
  380. int
  381. rdnin(buf,n,timeout)
  382.     unsigned char * buf;    /* Where to place characters read    */
  383.     int n;            /* Number of characters to read        */
  384.     int timeout;        /* Timeout, in seconds            */
  385. {
  386.     static unsigned char *mybuf = NULL;
  387.                 /* Dynamically allocated local buffer */
  388.     static int mybuflen = 0;
  389.                 /* Current size of local buffer    */
  390.     int escape_seen;    /* 1 => last character of a read was an ESC */
  391.     int nread;        /* Number of chars returned by timed_read() */
  392.     unsigned char c;
  393.     int i;
  394.  
  395.     /* Make sure local buffer is big enough
  396.      */
  397.     if ( n > mybuflen ){
  398.         if ( mybuf ){
  399.             free( mybuf );
  400.         }
  401.         mybuf = (unsigned char *) malloc( mybuflen=n );
  402.     }
  403.  
  404.  
  405.     /* More than one loop will be necessary if there are any
  406.      * escape sequences in the input
  407.      */
  408.     escape_seen = 0;
  409.     while ( n ){
  410.         nread = timed_read(mybuf,n,timeout);
  411.         if ( nread <= 0 ){
  412.             return 0;    /* TIMED OUT */
  413.         }
  414.  
  415.         /* Copy characters from local buffer to caller's buffer,
  416.          * converting escape sequences as they're encountered.
  417.          */
  418.         for ( i = 0; i < nread; i++ ){
  419.             c = mybuf[i];
  420.             if ( escape_seen ){
  421.                 escape_seen = 0;
  422.                 c &= ~0x40;
  423.             } else if ( c == ESC ){
  424.                 if ( ++i >= nread ){
  425.                     /* Need to refill local buffer */
  426.                     escape_seen = 1;
  427.                     break;
  428.                 }
  429.                 c = mybuf[i] & ~0x40;
  430.             }
  431.             *buf++ = c;
  432.             n--;
  433.         }
  434.     }
  435.     return 1;
  436. }
  437.  
  438.  
  439. /******************************************************************************
  440.  * getpkt:
  441.  *    Read a packet from a remote NINDY, with error checking, into the
  442.  *    indicated buffer.
  443.  *
  444.  *    Return packet status byte on success, TIMEOUT on failure.
  445.  ******************************************************************************/
  446. static
  447. int
  448. getpkt(buf)
  449.      unsigned char *buf;
  450. {
  451.     int i;
  452.     unsigned char hdr[3];    /* Packet header:
  453.                  *    hdr[0] = low byte of message length
  454.                  *    hdr[1] = high byte of message length
  455.                  *    hdr[2] = message status
  456.                  */
  457.     int cnt;        /* Message length (status byte + data)    */
  458.     unsigned char cs_calc;    /* Checksum calculated            */
  459.     unsigned char cs_recv;    /* Checksum received            */
  460.     static char errfmt[] =
  461.             "Bad checksum (recv=0x%02x; calc=0x%02x); retrying\r\n";
  462.  
  463.     while (1){
  464.         if ( !rdnin(hdr,3,5) ){
  465.             return TIMEOUT;
  466.         }
  467.         cnt = (hdr[1]<<8) + hdr[0] - 1;
  468.                     /* -1 for status byte (already read) */
  469.  
  470.         /* Caller's buffer may only be big enough for message body,
  471.          * without status byte and checksum, so make sure to read
  472.          * checksum into a separate buffer.
  473.          */
  474.         if ( !rdnin(buf,cnt,5) || !rdnin(&cs_recv,1,5) ){
  475.             return TIMEOUT;
  476.         }
  477.  
  478.         /* Calculate checksum
  479.          */
  480.         cs_calc = hdr[0] + hdr[1] + hdr[2];
  481.         for ( i = 0; i < cnt; i++ ){
  482.             cs_calc += buf[i];
  483.         }
  484.         if ( cs_calc == cs_recv ){
  485.             write (nindy_fd, "+", 1);
  486.             return hdr[2];
  487.         }
  488.     
  489.         /* Bad checksum: report, send NAK, and re-receive
  490.          */
  491.         fprintf(stderr, errfmt, cs_recv, cs_calc );
  492.         write (nindy_fd, "-", 1);
  493.     }
  494. }
  495.  
  496.  
  497. /******************************************************************************
  498.  * putpkt:
  499.  *    Send a packet to NINDY, checksumming it and converting special
  500.  *    characters to escape sequences.
  501.  ******************************************************************************/
  502.  
  503. /* This macro puts the character 'c' into the buffer pointed at by 'p',
  504.  * and increments the pointer.  If 'c' is one of the 4 special characters
  505.  * in the transmission protocol, it is converted into a 2-character
  506.  * escape sequence.
  507.  */
  508. #define PUTBUF(c,p)                        \
  509.     if ( c == DLE || c == ESC || c == XON || c == XOFF ){    \
  510.         *p++ = ESC;                    \
  511.         *p++ = c | 0x40;                \
  512.     } else {                        \
  513.         *p++ = c;                    \
  514.     }
  515.  
  516. static
  517. putpkt( msg, len )
  518.     unsigned char *msg;    /* Command to be sent, without lead ^P (\020) or checksum */
  519.     int len;    /* Number of bytes in message            */
  520. {
  521.     static char *buf = NULL;/* Local buffer -- build packet here    */
  522.     static int maxbuf = 0;    /* Current length of buffer        */
  523.     unsigned char ack;    /* Response received from NINDY        */
  524.     unsigned char checksum;    /* Packet checksum            */
  525.     char *p;        /* Pointer into buffer            */
  526.     int lenhi, lenlo;     /* High and low bytes of message length    */
  527.     int i;
  528.  
  529.  
  530.     /* Make sure local buffer is big enough.  Must include space for
  531.      * packet length, message body, and checksum.  And in the worst
  532.      * case, each character would expand into a 2-character escape
  533.      * sequence.
  534.      */
  535.     if ( maxbuf < ((2*len)+10) ){
  536.         if ( buf ){
  537.             free( buf );
  538.         }
  539.         buf = malloc( maxbuf=((2*len)+10) );
  540.     }
  541.  
  542.     /* Attention, NINDY!
  543.      */
  544.     write( nindy_fd, "\020", 1 );
  545.  
  546.  
  547.     lenlo = len & 0xff;
  548.     lenhi = (len>>8) & 0xff;
  549.     checksum = lenlo + lenhi;
  550.     p = buf;
  551.  
  552.     PUTBUF( lenlo, p );
  553.     PUTBUF( lenhi, p );
  554.  
  555.     for ( i=0; i<len; i++ ){
  556.         PUTBUF( msg[i], p );
  557.         checksum += msg[i];
  558.     }
  559.  
  560.     PUTBUF( checksum, p );
  561.  
  562.     /* Send checksummed message over and over until we get a positive ack
  563.      */
  564.     write( nindy_fd, buf, p-buf );
  565.     while (1){
  566.         if ( !rdnin(&ack,1,5) ){
  567.             /* timed out */
  568.             fprintf(stderr,"ACK timed out; resending\r\n");
  569.             write(nindy_fd,"\020",1);/* Attention, NINDY! */
  570.             write( nindy_fd, buf, p-buf );
  571.         } else if ( ack == '+' ){
  572.             return;
  573.         } else if ( ack == '-' ){
  574.             fprintf( stderr, "Remote NAK; resending\r\n" );
  575.             write( nindy_fd, buf, p-buf );
  576.         } else {
  577.             fprintf( stderr, "Bad ACK, ignored: <%c>\r\n", ack );
  578.         }
  579.     }
  580. }
  581.  
  582.  
  583.  
  584. /******************************************************************************
  585.  * send:
  586.  *    Send a message to a remote NINDY.  Check message status byte
  587.  *    for error responses.  If no error, return NINDY reponse (if any).
  588.  ******************************************************************************/
  589. static
  590. send( out, len, in )
  591.     unsigned char *out;    /* Message to be sent to NINDY            */
  592.     int len;        /* Number of meaningful bytes in out buffer    */
  593.     unsigned char *in;    /* Where to put response received from NINDY    */
  594. {
  595.     char *fmt;
  596.     int status;
  597.     static char *errmsg[] = {
  598.         "",                        /* 0 */
  599.         "Buffer overflow",                /* 1 */
  600.         "Unknown command",                /* 2 */
  601.         "Wrong amount of data to load register(s)",    /* 3 */
  602.         "Missing command argument(s)",            /* 4 */
  603.         "Odd number of digits sent to load memory",    /* 5 */
  604.         "Unknown register name",            /* 6 */
  605.         "No such memory segment",            /* 7 */
  606.         "No breakpoint available",            /* 8 */
  607.         "Can't set requested baud rate",        /* 9 */
  608.     };
  609. #    define NUMERRS    ( sizeof(errmsg) / sizeof(errmsg[0]) )
  610.  
  611.     static char err1[] = "Unknown error response from NINDY: #%d\r\n";
  612.     static char err2[] = "Error response #%d from NINDY: %s\r\n";
  613.  
  614.     while (1){
  615.         putpkt(out,len);
  616.         status = getpkt(in);
  617.         if ( status == TIMEOUT ){
  618.             fprintf( stderr, "Response timed out; resending\r\n" );
  619.         } else {
  620.             break;
  621.         }
  622.     }
  623.  
  624.     if ( status ){
  625.         fmt =  status > NUMERRS ? err1 : err2;
  626.         fprintf( stderr, fmt, status, errmsg[status] );
  627.         abort();
  628.     }
  629. }
  630.  
  631.         /************************
  632.          *                      *
  633.          *  BAUD RATE ROUTINES  *
  634.          *                      *
  635.          ************************/
  636.  
  637. /* Table of baudrates known to be acceptable to NINDY.  Each baud rate
  638.  * appears both as character string and as a Unix baud rate constant.
  639.  */
  640. struct baudrate {
  641.     char *string;
  642.     int rate;
  643. };
  644.  
  645. static struct baudrate baudtab[] = {
  646.      "1200", B1200,
  647.      "2400", B2400,
  648.      "4800", B4800,
  649.      "9600", B9600,
  650.     "19200", B19200,
  651.     "38400", B38400,
  652.     NULL,    0        /* End of table */
  653. };
  654.  
  655.  
  656. /******************************************************************************
  657.  * parse_baudrate:
  658.  *    Look up the passed baud rate in the baudrate table.  If found, change
  659.  *    our internal record of the current baud rate, but don't do anything
  660.  *    about the tty just now.
  661.  *
  662.  *    Return pointer to baudrate structure on success, NULL on failure.
  663.  ******************************************************************************/
  664. static
  665. struct baudrate *
  666. parse_baudrate(s)
  667.     char *s;    /* Desired baud rate, as an ASCII (decimal) string */
  668. {
  669.     int i;
  670.  
  671.     for ( i=0; baudtab[i].string != NULL; i++ ){
  672.         if ( !strcmp(baudtab[i].string,s) ){
  673.             return &baudtab[i];
  674.         }
  675.     }
  676.     return NULL;
  677. }
  678.  
  679. /******************************************************************************
  680.  * try_baudrate:
  681.  *    Try speaking to NINDY via the specified file descriptor at the
  682.  *    specified baudrate.  Assume success if we can send an empty command
  683.  *    with a bogus checksum and receive a NAK (response of '-') back within
  684.  *    one second.
  685.  *
  686.  *    Return 1 on success, 0 on failure.
  687.  ******************************************************************************/
  688.  
  689. static int
  690. try_baudrate( fd, brp )
  691.     int fd;
  692.     struct baudrate *brp;
  693. {
  694.     TTY_STRUCT tty;
  695.     unsigned char c;
  696.     
  697.  
  698.     /* Set specified baud rate and flush all pending input */
  699.     ioctl( fd, TIOCGETP, &tty );
  700.     TTY_REMOTE( tty, brp->rate );
  701.     ioctl( fd, TIOCSETP, &tty );
  702.     tty_flush( fd );
  703.  
  704.     /* Send empty command with bad checksum, hope for NAK ('-') response */
  705.     write( fd, "\020\0\0\001", 4 );
  706.     if ( !rdnin(&c,1,1) ){
  707.         /* timed out */
  708.         return 0;
  709.     } else {
  710.         return (c == '-');
  711.     }
  712. }
  713.  
  714. /******************************************************************************
  715.  * autobaud:
  716.  *    Get NINDY talking over the specified file descriptor at the specified
  717.  *    baud rate.  First see if NINDY's already talking at 'baudrate'.  If
  718.  *    not, run through all the legal baudrates in 'baudtab' until one works,
  719.  *    and then tell NINDY to talk at 'baudrate' instead.
  720.  ******************************************************************************/
  721. static
  722. autobaud( fd, brp )
  723.     int fd;
  724.     struct baudrate *brp;
  725. {
  726.     int i;
  727.     TTY_STRUCT tty;
  728.     int failures;
  729.  
  730.  
  731.     say("NINDY at wrong baud rate? Trying to autobaud...\n");
  732.     failures = i = 0;
  733.     while ( 1 ){
  734.         say( "\r%s...   ", baudtab[i].string );
  735.         if ( try_baudrate(fd, &baudtab[i]) ){
  736.             break;
  737.         }
  738.         if ( baudtab[++i].string == NULL ){
  739.             /* End of table -- wraparound */
  740.             i = 0;
  741.             if ( failures++ ){
  742.                 say("\nAutobaud failed again.  Giving up.\n");
  743.                 exit(1);
  744.             } else {
  745.                 say("\nAutobaud failed. Trying again...\n");
  746.             }
  747.         }
  748.     }
  749.  
  750.     /* Found NINDY's current baud rate;  now change it.
  751.      */
  752.     say("Changing NINDY baudrate to %s\n", brp->string);
  753.     ninBaud( brp->string );
  754.  
  755.     /* Change our baud rate back to rate to which we just set NINDY.
  756.      */
  757.     ioctl( fd, TIOCGETP, &tty );
  758.     TTY_REMOTE( tty, brp->rate );
  759.     ioctl( fd, TIOCSETP, &tty );
  760. }
  761.  
  762. /*****************************************************************************
  763.  * coffstrip:
  764.  *    Passed the name of an executable object file in either b.out or
  765.  *    COFF format.
  766.  *
  767.  *    If the file is in b.out format, it is converted to little-endian
  768.  *    COFF format (i.e., the format suitable for downloading to NINDY).
  769.  *    In either case, the COFF file is then stripped of all relocation
  770.  *    and symbol information, to speed up its download.
  771.  *
  772.  * RETURNS:
  773.  *    pointer to the name of the stripped COFF file (a tmp file that has
  774.  *    been created and closed); NULL on error.
  775.  *****************************************************************************/
  776.  
  777. #define STRIP    "bfd_strip"    /* Name of bfd strip utility    */
  778. #define NINDY_OBJ    "coff-Intel-little"
  779.  
  780. char *
  781. coffstrip( fn )
  782.     char *fn;    /* Name of object file */
  783. {
  784.     extern char *mktemp();
  785.     static char template[] = "/tmp/commXXXXXX";
  786.     static char newfile[sizeof template];
  787.     char *strip;    /* Pointer to full pathname of strip utility    */
  788.     int success;    /* Return value                    */
  789.     int pid;    /* Process ID of xmodem transfer utility    */
  790.     WAITTYPE w;    /* xmodem transfer completion status        */
  791.     int wret;    /* Value returned by wait            */
  792.     char *tempfile;    /* Stripped copy of object file            */
  793.     char buf[400];
  794.  
  795.  
  796.     strcpy (newfile, template);
  797.     tempfile = mktemp( newfile );
  798.  
  799.     /* Make sure the strip utility is findable.
  800.      */
  801.     if ( ((strip = exists("G960BIN",STRIP,NULL,NULL,1)) == NULL)
  802.     &&   ((strip = exists("G960BASE","bin",STRIP, NULL,1)) == NULL)
  803. #ifdef HOST
  804.     &&   ((strip = exists(DEFAULT_BASE,HOST,"bin",STRIP,0)) == NULL)
  805. #endif
  806.     ){
  807.         fprintf(stderr,"Can't find '%s' utility\n",STRIP);
  808.         fprintf(stderr,"Check env variables G960BIN and G960BASE\n");
  809.         return NULL;
  810.     }
  811.  
  812.     success = 0;
  813.     sprintf( buf, "cp %s %s", fn, tempfile );
  814.     printf ("%s\n", buf);
  815.     if ( system(buf) == 0 ){
  816.         sprintf( buf, "%s %s -T %s", strip, tempfile, NINDY_OBJ );
  817.         printf ("%s\n", buf);
  818.         if ( system(buf) == 0 ){
  819.             return tempfile;
  820.         }
  821.     }
  822.  
  823.     return NULL;
  824. }
  825.  
  826.         /**********************************
  827.          *                  *
  828.          *   NINDY INTERFACE ROUTINES      *
  829.          *                                  *
  830.          * ninConnect *MUST* be the first *
  831.          * one of these routines called.  *
  832.          **********************************/
  833.  
  834.  
  835. /******************************************************************************
  836.  * ninBaud:
  837.  *    Ask NINDY to change the baud rate on its serial port.
  838.  *    Assumes we know the baud rate at which NINDY's currently talking.
  839.  ******************************************************************************/
  840. ninBaud( baudrate )
  841.     char *baudrate;    /* Desired baud rate, as a string of ASCII decimal
  842.              * digits.
  843.              */
  844. {
  845.     unsigned char msg[100];
  846.  
  847.     if ( old_nindy ){
  848.         OninBaud( baudrate );
  849.         return;
  850.     }
  851.  
  852.     tty_flush( nindy_fd );
  853.  
  854.     /* Can't use "send" because NINDY reply will be unreadable after
  855.      * baud rate change.
  856.      */
  857.     sprintf( msg, "z%s", baudrate );
  858.     putpkt( msg, strlen(msg)+1 );    /* "+1" to send terminator too */
  859. }
  860.  
  861.  
  862. /******************************************************************************
  863.  * ninBptDel:
  864.  *    Ask NINDY to delete the specified type of *hardware* breakpoint at
  865.  *    the specified address.  If the 'addr' is -1, all breakpoints of
  866.  *    the specified type are deleted.
  867.  ******************************************************************************/
  868. ninBptDel( addr, type )
  869.     long addr;    /* Address in 960 memory    */
  870.     char type;    /* 'd' => data bkpt, 'i' => instruction breakpoint */
  871. {
  872.     unsigned char buf[10];
  873.  
  874.     if ( old_nindy ){
  875.         OninBptDel( addr, type == 'd' ? 1 : 0 );
  876.         return;
  877.     }
  878.  
  879.     buf[0] = 'b';
  880.     buf[1] = type;
  881.  
  882.     if ( addr == -1 ){
  883.         send( buf, 2, NULL );
  884.     } else {
  885.         put_int( &buf[2], addr );
  886.         send( buf, 6, NULL );
  887.     }
  888. }
  889.  
  890.  
  891. /******************************************************************************
  892.  * ninBptSet:
  893.  *    Ask NINDY to set the specified type of *hardware* breakpoint at
  894.  *    the specified address.
  895.  ******************************************************************************/
  896. ninBptSet( addr, type )
  897.     long addr;    /* Address in 960 memory    */
  898.     char type;    /* 'd' => data bkpt, 'i' => instruction breakpoint */
  899. {
  900.     unsigned char buf[10];
  901.  
  902.     if ( old_nindy ){
  903.         OninBptSet( addr, type == 'd' ? 1 : 0 );
  904.         return;
  905.     }
  906.  
  907.  
  908.     buf[0] = 'B';
  909.     buf[1] = type;
  910.     put_int( &buf[2], addr );
  911.     send( buf, 6, NULL );
  912. }
  913.  
  914.  
  915. /******************************************************************************
  916.  * ninConnect:
  917.  *    Open the specified tty.  Get communications working at the specified
  918.  *    baud rate.  Flush any pending I/O on the tty.
  919.  *
  920.  *    Return the file descriptor, or -1 on failure.
  921.  ******************************************************************************/
  922. int
  923. ninConnect( name, baudrate, brk, silent, old_protocol )
  924.     char *name;        /* "/dev/ttyXX" to be opened            */
  925.     char *baudrate;/* baud rate: a string of ascii decimal digits (eg,"9600")*/
  926.     int brk;        /* 1 => send break to tty first thing after opening it*/
  927.     int silent;        /* 1 => stifle unnecessary messages when talking to 
  928.              *    this tty.
  929.              */
  930.     int old_protocol;
  931. {
  932.     int i;
  933.     char *p;
  934.     struct baudrate *brp;
  935.  
  936.     /* We will try each of the following paths when trying to open the tty
  937.      */
  938.     static char *prefix[] = { "", "/dev/", "/dev/tty", NULL };
  939.  
  940.     if ( old_protocol ){
  941.         old_nindy = 1;
  942.         return OninConnect( name, baudrate, brk, silent );
  943.     }
  944.  
  945.     quiet = silent;        /* Make global to this file */
  946.  
  947.     for ( i=0; prefix[i] != NULL; i++ ){
  948.         p = malloc(strlen(prefix[i]) + strlen(name) + 1 );
  949.         strcpy( p, prefix[i] );
  950.         strcat( p, name );
  951.         nindy_fd = open(p,O_RDWR);
  952.         if ( nindy_fd >= 0 ){
  953. #ifdef TIOCEXCL
  954.             /* Exclusive use mode (hp9000 does not support it) */
  955.             ioctl(nindy_fd,TIOCEXCL,NULL);
  956. #endif
  957.             if ( brk ){
  958.                 send_break( nindy_fd );
  959.             }
  960.  
  961.             brp = parse_baudrate( baudrate );
  962.             if ( brp == NULL ){
  963.                 say("Illegal baudrate %s ignored; using 9600\n",
  964.                                 baudrate);
  965.                 brp = parse_baudrate( "9600" );
  966.             }
  967.  
  968.             if ( !try_baudrate(nindy_fd,brp) ){
  969.                 autobaud(nindy_fd,brp);
  970.             }
  971.             tty_flush( nindy_fd );
  972.             say( "Connected to %s\n", p );
  973.             free(p);
  974.             break;
  975.         }
  976.         free(p);
  977.     }
  978.     return nindy_fd;
  979. }
  980.  
  981.  
  982.  
  983. /******************************************************************************
  984.  * ninDownload:
  985.  *    Ask NINDY to start up it's COFF downloader. Invoke 'sx' to perform
  986.  *    the XMODEM download from the host end.
  987.  *
  988.  *    Return 1 on success, 0 on failure.
  989.  ******************************************************************************/
  990.  
  991. #define XMODEM    "sx"    /* Name of xmodem transfer utility    */
  992.  
  993. int
  994. ninDownload( fn, quiet )
  995.     char *fn;        /* Stripped copy of object file            */
  996.     int quiet;
  997. {
  998.     char *p;    /* Pointer to full pathname of sx utility    */
  999.     int success;    /* Return value                    */
  1000.     int pid;    /* Process ID of xmodem transfer utility    */
  1001.     WAITTYPE w;    /* xmodem transfer completion status        */
  1002.     int wret;    /* Value returned by wait            */
  1003.     char buf[200];
  1004.  
  1005.  
  1006.     if ( old_nindy ){
  1007.         return OninDownload( fn, quiet );
  1008.     }
  1009.  
  1010.     /* Make sure the xmodem utility is findable.  This must be done before
  1011.      * we start up the NINDY end of the download (NINDY will hang if we
  1012.      * don't complete the download).
  1013.      */
  1014.     if ( ((p = exists("G960BIN",XMODEM,NULL,NULL,1)) == NULL)
  1015.     &&   ((p = exists("G960BASE","bin",XMODEM, NULL,1)) == NULL)
  1016. #ifdef HOST
  1017.     &&   ((p = exists(DEFAULT_BASE,HOST,"bin",XMODEM,0)) == NULL)
  1018. #endif
  1019.                                       ){
  1020.  
  1021.         fprintf(stderr,"Can't find '%s' download utility\n",XMODEM);
  1022.         fprintf(stderr,"Check env variables G960BIN and G960BASE\n");
  1023.         return 0;
  1024.     }
  1025.  
  1026.     if ( !quiet ){
  1027.         printf( "Downloading %s\n", fn );
  1028.     }
  1029.  
  1030.     /* Reset NINDY,  wait until "reset-complete" ack,
  1031.      * and start up the NINDY end of the download.
  1032.      */
  1033.     ninReset();
  1034.     putpkt((unsigned char *) "D", 1 );
  1035.  
  1036.     /* Invoke x-modem transfer, a separate process.  DON'T
  1037.      * use system() to do this -- under system V Unix, the
  1038.      * redirection of stdin/stdout causes the nindy tty to
  1039.      * lose all the transmission parameters we've set up.
  1040.      */
  1041.     success = 0;
  1042.  
  1043. #if defined(USG) && !defined(HAVE_VFORK)
  1044.     pid = fork ();
  1045. #else
  1046.     pid = vfork ();
  1047. #endif
  1048.     if ( pid == -1 ){
  1049.         perror( "Can't fork process:" );
  1050.  
  1051.     } else if ( pid == 0 ){        /* CHILD */
  1052.         dup2( nindy_fd, 0 );    /* Redirect stdin */
  1053.         dup2( nindy_fd, 1 );    /* Redirect stout */
  1054.         if ( quiet ){
  1055.             execl( p, p, "-q", fn, (char*)0 );
  1056.         } else {
  1057.             execl( p, p, fn, (char*)0 );
  1058.         }
  1059.         /* Don't get here unless execl fails */
  1060.         sprintf( buf, "Can't exec %s", p );
  1061.         perror( buf );
  1062.  
  1063.     } else {            /* PARENT */
  1064.         do {
  1065.             wret = wait(&w);
  1066.         } while ( wret != pid && wret != -1 );
  1067.  
  1068.         if ( wret == -1 ){
  1069.             perror( "Wait failed" );
  1070.         } else if (WIFEXITED(w) && (WEXITSTATUS(w) == 0)){
  1071.             success = 1;
  1072.         }
  1073.     }
  1074.     return success;
  1075. }
  1076.  
  1077.  
  1078. /******************************************************************************
  1079.  * ninGdbExit:
  1080.  *    Ask NINDY to leave GDB mode and print a NINDY prompt.
  1081.  ******************************************************************************/
  1082. ninGdbExit()
  1083. {
  1084.     if ( old_nindy ){
  1085.         OninGdbExit();
  1086.         return;
  1087.     }
  1088.         putpkt((unsigned char *) "E", 1 );
  1089. }
  1090.  
  1091.  
  1092. /******************************************************************************
  1093.  * ninGo:
  1094.  *    Ask NINDY to start or continue execution of an application program
  1095.  *    in it's memory at the current ip.
  1096.  ******************************************************************************/
  1097. ninGo( step_flag )
  1098.     int step_flag;    /* 1 => run in single-step mode */
  1099. {
  1100.     if ( old_nindy ){
  1101.         OninGo( step_flag );
  1102.         return;
  1103.     }
  1104.     putpkt((unsigned char *) (step_flag ? "s" : "c"), 1 );
  1105. }
  1106.  
  1107.  
  1108. /******************************************************************************
  1109.  * ninMemGet:
  1110.  *    Read a string of bytes from NINDY's address space (960 memory).
  1111.  ******************************************************************************/
  1112. ninMemGet(ninaddr, hostaddr, len)
  1113.      long ninaddr;    /* Source address, in the 960 memory space    */
  1114.      unsigned char *hostaddr;    /* Destination address, in our memory space */
  1115.      int len;        /* Number of bytes to read            */
  1116. {
  1117.     unsigned char buf[BUFSIZE+20];
  1118.     int cnt;        /* Number of bytes in next transfer    */
  1119.  
  1120.     if ( old_nindy ){
  1121.         OninMemGet(ninaddr, hostaddr, len);
  1122.         return;
  1123.     }
  1124.  
  1125.     for ( ; len > 0; len -= BUFSIZE ){
  1126.         cnt = len > BUFSIZE ? BUFSIZE : len;
  1127.  
  1128.         buf[0] = 'm';
  1129.         put_int( &buf[1], ninaddr );
  1130.         buf[5] = cnt & 0xff;
  1131.         buf[6] = (cnt>>8) & 0xff;
  1132.  
  1133.         send( buf, 7, hostaddr );
  1134.  
  1135.         ninaddr += cnt;
  1136.         hostaddr += cnt;
  1137.     }
  1138. }
  1139.  
  1140.  
  1141. /******************************************************************************
  1142.  * ninMemPut:
  1143.  *    Write a string of bytes into NINDY's address space (960 memory).
  1144.  ******************************************************************************/
  1145. ninMemPut( ninaddr, hostaddr, len )
  1146.      long ninaddr;    /* Destination address, in NINDY memory space    */
  1147.      unsigned char *hostaddr;    /* Source address, in our memory space    */
  1148.      int len;        /* Number of bytes to write            */
  1149. {
  1150.     unsigned char buf[BUFSIZE+20];
  1151.     int cnt;        /* Number of bytes in next transfer    */
  1152.  
  1153.     if ( old_nindy ){
  1154.         OninMemPut( ninaddr, hostaddr, len );
  1155.         return;
  1156.     }
  1157.     for ( ; len > 0; len -= BUFSIZE ){
  1158.         cnt = len > BUFSIZE ? BUFSIZE : len;
  1159.  
  1160.         buf[0] = 'M';
  1161.         put_int( &buf[1], ninaddr );
  1162.         bcopy( hostaddr, buf+5, cnt );
  1163.         send( buf, cnt+5, NULL );
  1164.  
  1165.         ninaddr += cnt;
  1166.         hostaddr += cnt;
  1167.     }
  1168. }
  1169.  
  1170. /******************************************************************************
  1171.  * ninRegGet:
  1172.  *    Retrieve the contents of a 960 register, and return them as a long
  1173.  *    in host byte order.
  1174.  *
  1175.  *    THIS ROUTINE CAN ONLY BE USED TO READ THE LOCAL, GLOBAL, AND
  1176.  *    ip/ac/pc/tc REGISTERS.
  1177.  *
  1178.  ******************************************************************************/
  1179. long
  1180. ninRegGet( regname )
  1181.     char *regname;    /* Register name recognized by NINDY, subject to the
  1182.              * above limitations.
  1183.              */
  1184. {
  1185.     unsigned char outbuf[10];
  1186.     unsigned char inbuf[20];
  1187.  
  1188.     if ( old_nindy ){
  1189.         return OninRegGet( regname );
  1190.     }
  1191.  
  1192.     sprintf( outbuf, "u%s:", regname );
  1193.     send( outbuf, strlen(outbuf), inbuf );
  1194.     return get_int(inbuf);
  1195. }
  1196.  
  1197. /******************************************************************************
  1198.  * ninRegPut:
  1199.  *    Set the contents of a 960 register.
  1200.  *
  1201.  *    THIS ROUTINE CAN ONLY BE USED TO SET THE LOCAL, GLOBAL, AND
  1202.  *    ip/ac/pc/tc REGISTERS.
  1203.  *
  1204.  ******************************************************************************/
  1205. ninRegPut( regname, val )
  1206.     char *regname;    /* Register name recognized by NINDY, subject to the
  1207.              * above limitations.
  1208.              */
  1209.     long val;        /* New contents of register, in host byte-order    */
  1210. {
  1211.     unsigned char buf[20];
  1212.     int len;
  1213.  
  1214.     if ( old_nindy ){
  1215.         OninRegPut( regname, val );
  1216.         return;
  1217.     }
  1218.  
  1219.     sprintf( buf, "U%s:", regname );
  1220.     len = strlen(buf);
  1221.     put_int( &buf[len], val );
  1222.     send( buf, len+4, NULL );
  1223. }
  1224.  
  1225. /******************************************************************************
  1226.  * ninRegsGet:
  1227.  *    Get a dump of the contents of the entire 960 register set.  The
  1228.  *    individual registers appear in the dump in the following order:
  1229.  *
  1230.  *        pfp  sp   rip  r3   r4   r5   r6   r7 
  1231.  *        r8   r9   r10  r11  r12  r13  r14  r15 
  1232.  *        g0   g1   g2   g3   g4   g5   g6   g7 
  1233.  *        g8   g9   g10  g11  g12  g13  g14  fp 
  1234.  *        pc   ac   ip   tc   fp0  fp1  fp2  fp3
  1235.  *
  1236.  *    Each individual register comprises exactly 4 bytes, except for
  1237.  *    fp0-fp3, which are 8 bytes.  All register values are in 960
  1238.  *    (little-endian) byte order.
  1239.  *
  1240.  ******************************************************************************/
  1241. ninRegsGet( regp )
  1242.     unsigned char *regp;        /* Where to place the register dump */
  1243. {
  1244.     if ( old_nindy ){
  1245.         OninRegsGet( regp );
  1246.         return;
  1247.     }
  1248.     send( (unsigned char *) "r", 1, regp );
  1249. }
  1250.  
  1251.  
  1252. /******************************************************************************
  1253.  * ninRegsPut:
  1254.  *    Initialize the entire 960 register set to a specified set of values.
  1255.  *    The format of the register value data should be the same as that
  1256.  *    returned by ninRegsGet.
  1257.  *
  1258.  * WARNING:
  1259.  *    All register values must be in 960 (little-endian) byte order.
  1260.  *
  1261.  ******************************************************************************/
  1262. ninRegsPut( regp )
  1263.     char *regp;        /* Pointer to desired values of registers */
  1264. {
  1265.     unsigned char buf[REGISTER_BYTES+10];
  1266.  
  1267.     if ( old_nindy ){
  1268.         OninRegsPut( regp );
  1269.         return;
  1270.     }
  1271.  
  1272.     buf[0] = 'R';
  1273.     bcopy( regp, buf+1, REGISTER_BYTES );
  1274.     send( buf, REGISTER_BYTES+1, NULL );
  1275. }
  1276.  
  1277.  
  1278. /******************************************************************************
  1279.  * ninReset:
  1280.  *      Ask NINDY to perform a soft reset; wait for the reset to complete.
  1281.  *
  1282.  ******************************************************************************/
  1283. ninReset()
  1284. {
  1285.     unsigned char ack;
  1286.  
  1287.     if ( old_nindy ){
  1288.         OninReset();
  1289.         return;
  1290.     }
  1291.  
  1292.     while (1){
  1293.         putpkt((unsigned char *) "X", 1 );
  1294.         while (1){
  1295.             if ( !rdnin(&ack,1,5) ){
  1296.                 /* Timed out */
  1297.                 break;        /* Resend */
  1298.             }
  1299.             if ( ack == '+' ){
  1300.                 return;
  1301.             }
  1302.         }
  1303.     }
  1304. }
  1305.  
  1306.  
  1307. /******************************************************************************
  1308.  * ninSrq:
  1309.  *    Assume NINDY has stopped execution of the 960 application program in
  1310.  *    order to process a host service request (srq).  Ask NINDY for the
  1311.  *    srq arguments, perform the requested service, and send an "srq
  1312.  *    complete" message so NINDY will return control to the application.
  1313.  *
  1314.  ******************************************************************************/
  1315. ninSrq()
  1316. {
  1317.     unsigned char buf[BUFSIZE];
  1318.     int retcode;
  1319.     unsigned char srqnum;
  1320.     int i;
  1321.     int offset;
  1322.     int arg[MAX_SRQ_ARGS];
  1323.  
  1324.     if ( old_nindy ){
  1325.         OninSrq();
  1326.         return;
  1327.     }
  1328.  
  1329.  
  1330.     /* Get srq number and arguments
  1331.      */
  1332.     send((unsigned char *) "!", 1, buf );
  1333.  
  1334.     srqnum = buf[0];
  1335.     for  ( i=0, offset=1; i < MAX_SRQ_ARGS; i++, offset+=4 ){
  1336.         arg[i] = get_int(&buf[offset]);
  1337.     }
  1338.  
  1339.     /* Process Srq
  1340.      */
  1341.     switch( srqnum ){
  1342.     case BS_CLOSE:
  1343.         /* args: file descriptor */
  1344.         if ( arg[0] > 2 ){
  1345.             retcode = close( arg[0] );
  1346.         } else {
  1347.             retcode = 0;
  1348.         }
  1349.         break;
  1350.     case BS_CREAT:
  1351.         /* args: filename, mode */
  1352.         ninStrGet( arg[0], buf );
  1353.         retcode = creat(buf,arg[1]);
  1354.         break;
  1355.     case BS_OPEN:
  1356.         /* args: filename, flags, mode */
  1357.         ninStrGet( arg[0], buf );
  1358.         retcode = open(buf,arg[1],arg[2]);
  1359.         break;
  1360.     case BS_READ:
  1361.         /* args: file descriptor, buffer, count */
  1362.         retcode = read(arg[0],buf,arg[2]);
  1363.         if ( retcode > 0 ){
  1364.             ninMemPut( arg[1], buf, retcode );
  1365.         }
  1366.         break;
  1367.     case BS_SEEK:
  1368.         /* args: file descriptor, offset, whence */
  1369.         retcode = lseek(arg[0],arg[1],arg[2]);
  1370.         break;
  1371.     case BS_WRITE:
  1372.         /* args: file descriptor, buffer, count */
  1373.         ninMemGet( arg[1], buf, arg[2] );
  1374.         retcode = write(arg[0],buf,arg[2]);
  1375.         break;
  1376.     default:
  1377.         retcode = ERROR;
  1378.         break;
  1379.     }
  1380.  
  1381.     /* Send request termination status to NINDY
  1382.      */
  1383.     buf[0] = 'e';
  1384.     put_int( &buf[1], retcode );
  1385.     send( buf, 5, NULL );
  1386. }
  1387.  
  1388.  
  1389. /******************************************************************************
  1390.  * ninStopWhy:
  1391.  *    Assume the application program has stopped (i.e., a DLE was received
  1392.  *    from NINDY).  Ask NINDY for status information describing the
  1393.  *    reason for the halt.
  1394.  *
  1395.  *    Returns a non-zero value if the user program has exited, 0 otherwise.
  1396.  *    Also returns the following information, through passed pointers:
  1397.  *           - why: an exit code if program the exited; otherwise the reason
  1398.  *            why the program halted (see stop.h for values).
  1399.  *        - contents of register ip (little-endian byte order)
  1400.  *        - contents of register sp (little-endian byte order)
  1401.  *        - contents of register fp (little-endian byte order)
  1402.  ******************************************************************************/
  1403. char
  1404. ninStopWhy( whyp, ipp, fpp, spp )
  1405.     unsigned char *whyp; /* Return the 'why' code through this pointer    */
  1406.     long *ipp;    /* Return contents of register ip through this pointer    */
  1407.     long *fpp;    /* Return contents of register fp through this pointer    */
  1408.     long *spp;    /* Return contents of register sp through this pointer    */
  1409. {
  1410.     unsigned char buf[30];
  1411.     extern char OninStopWhy ();
  1412.  
  1413.     if ( old_nindy ){
  1414.         return OninStopWhy( whyp, ipp, fpp, spp );
  1415.     }
  1416.     send((unsigned char *) "?", 1, buf );
  1417.  
  1418.     *whyp = buf[1];
  1419.     bcopy (&buf[2],  (char *)ipp, sizeof (*ipp));
  1420.     bcopy (&buf[6],  (char *)fpp, sizeof (*ipp));
  1421.     bcopy (&buf[10], (char *)spp, sizeof (*ipp));
  1422.     return buf[0];
  1423. }
  1424.  
  1425. /******************************************************************************
  1426.  * ninStrGet:
  1427.  *    Read a '\0'-terminated string of data out of the 960 memory space.
  1428.  *
  1429.  ******************************************************************************/
  1430. static
  1431. ninStrGet( ninaddr, hostaddr )
  1432.      unsigned long ninaddr;    /* Address of string in NINDY memory space */
  1433.      unsigned char *hostaddr;    /* Address of the buffer to which string should
  1434.                  *    be copied.
  1435.                  */
  1436. {
  1437.     unsigned char cmd[5];
  1438.  
  1439.     cmd[0] = '"';
  1440.     put_int( &cmd[1], ninaddr );
  1441.     send( cmd, 5, hostaddr );
  1442. }
  1443.  
  1444. /******************************************************************************
  1445.  * ninVersion:
  1446.  *    Ask NINDY for version information about itself.
  1447.  *    The information is sent as an ascii string in the form "x.xx,<arch>",
  1448.  *    where,
  1449.  *        x.xx    is the version number
  1450.  *        <arch>    is the processor architecture: "KA", "KB", "MC", "CA" *
  1451.  *
  1452.  ******************************************************************************/
  1453. int
  1454. ninVersion( p )
  1455.      unsigned char *p;        /* Where to place version string */
  1456. {
  1457.  
  1458.     if ( old_nindy ){
  1459.         return OninVersion( p );
  1460.     }
  1461.     send((unsigned char *) "v", 1, p );
  1462.     return strlen(p);
  1463. }
  1464.